﻿using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using HslCommunication.BasicFramework;
using HslCommunication.Core;
using HslCommunication.Core.IMessage;
using HslCommunication.Core.Net;
using HslCommunication.Reflection;

namespace HslCommunication.Profinet.Siemens
{
	/// <summary>
	/// 使用了Fetch/Write协议来和西门子进行通讯，该种方法需要在PLC侧进行一些配置<br />
	/// Using the Fetch/write protocol to communicate with Siemens, this method requires some configuration on the PLC side
	/// </summary>
	/// <remarks>
	/// 配置的参考文章地址：https://www.cnblogs.com/dathlin/p/8685855.html
	/// <br />
	/// 与S7协议相比较而言，本协议不支持对单个的点位的读写操作。如果读取M100.0，需要读取M100的值，然后进行提取位数据。
	///
	/// 如果需要写入位地址的数据，可以读取plc的byte值，然后进行与或非，然后写入到plc之中。
	/// 地址支持的列表如下：
	/// <list type="table">
	///   <listheader>
	///     <term>地址名称</term>
	///     <term>地址代号</term>
	///     <term>示例</term>
	///     <term>地址进制</term>
	///     <term>字操作</term>
	///     <term>位操作</term>
	///     <term>备注</term>
	///   </listheader>
	///   <item>
	///     <term>中间寄存器</term>
	///     <term>M</term>
	///     <term>M100,M200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>输入寄存器</term>
	///     <term>I</term>
	///     <term>I100,I200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>输出寄存器</term>
	///     <term>Q</term>
	///     <term>Q100,Q200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>DB块寄存器</term>
	///     <term>DB</term>
	///     <term>DB1.100,DB1.200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>定时器的值</term>
	///     <term>T</term>
	///     <term>T100,T200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	///   <item>
	///     <term>计数器的值</term>
	///     <term>C</term>
	///     <term>C100,C200</term>
	///     <term>10</term>
	///     <term>√</term>
	///     <term>×</term>
	///     <term></term>
	///   </item>
	/// </list>
	/// </remarks>
	/// <example>
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\SiemensFetchWriteNet.cs" region="Usage" title="简单的短连接使用" />
	/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\SiemensFetchWriteNet.cs" region="Usage2" title="简单的长连接使用" />
	/// </example>
	// Token: 0x02000049 RID: 73
	public class SiemensFetchWriteNet : NetworkDeviceBase
	{
		/// <summary>
		/// 实例化一个西门子的Fetch/Write协议的通讯对象<br />
		/// Instantiate a communication object for a Siemens Fetch/write protocol
		/// </summary>
		// Token: 0x060005FF RID: 1535 RVA: 0x0001B81E File Offset: 0x00019A1E
		public SiemensFetchWriteNet()
		{
			base.WordLength = 2;
			base.ByteTransform = new ReverseBytesTransform();
		}

		/// <summary>
		/// 实例化一个西门子的Fetch/Write协议的通讯对象<br />
		/// Instantiate a communication object for a Siemens Fetch/write protocol
		/// </summary>
		/// <param name="ipAddress">PLC的Ip地址 -&gt; Specify IP Address</param>
		/// <param name="port">PLC的端口 -&gt; Specify IP Port</param>
		// Token: 0x06000600 RID: 1536 RVA: 0x0001B83C File Offset: 0x00019A3C
		public SiemensFetchWriteNet(string ipAddress, int port)
		{
			base.WordLength = 2;
			this.IpAddress = ipAddress;
			this.Port = port;
			base.ByteTransform = new ReverseBytesTransform();
		}

		/// <inheritdoc />
		// Token: 0x06000601 RID: 1537 RVA: 0x0001B86A File Offset: 0x00019A6A
		protected override INetMessage GetNewNetMessage()
		{
			return new FetchWriteMessage();
		}

		/// <summary>
		/// 从PLC读取数据，地址格式为I100，Q100，DB20.100，M100，T100，C100，以字节为单位<br />
		/// Read data from PLC, address format I100,Q100,DB20.100,M100,T100,C100, in bytes
		/// </summary>
		/// <param name="address">起始地址，格式为I100，M100，Q100，DB20.100，T100，C100 -&gt;
		/// Starting address, formatted as I100,M100,Q100,DB20.100,T100,C100
		/// </param>
		/// <param name="length">读取的数量，以字节为单位 -&gt; The number of reads, in bytes</param>
		/// <returns>带有成功标志的字节信息 -&gt; Byte information with a success flag</returns>
		/// <example>
		/// 假设起始地址为M100，M100存储了温度，100.6℃值为1006，M102存储了压力，1.23Mpa值为123，M104，M105，M106，M107存储了产量计数，读取如下：
		/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\SiemensFetchWriteNet.cs" region="ReadExample2" title="Read示例" />
		/// 以下是读取不同类型数据的示例
		/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\SiemensFetchWriteNet.cs" region="ReadExample1" title="Read示例" />
		/// </example>
		// Token: 0x06000602 RID: 1538 RVA: 0x0001B874 File Offset: 0x00019A74
		[HslMqttApi("ReadByteArray", "")]
		public override OperateResult<byte[]> Read(string address, ushort length)
		{
			OperateResult<byte[]> operateResult = SiemensFetchWriteNet.BuildReadCommand(address, length);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(operateResult.Content);
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = operateResult2;
				}
				else
				{
					OperateResult operateResult3 = SiemensFetchWriteNet.CheckResponseContent(operateResult2.Content);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = OperateResult.CreateFailedResult<byte[]>(operateResult3);
					}
					else
					{
						result = OperateResult.CreateSuccessResult<byte[]>(SoftBasic.ArrayRemoveBegin<byte>(operateResult2.Content, 16));
					}
				}
			}
			return result;
		}

		/// <summary>
		/// 将数据写入到PLC数据，地址格式为I100，Q100，DB20.100，M100，以字节为单位<br />
		/// Writes data to the PLC data, in the address format i100,q100,db20.100,m100, in bytes
		/// </summary>
		/// <param name="address">起始地址，格式为M100,I100,Q100,DB1.100 -&gt; Starting address, formatted as M100,I100,Q100,DB1.100</param>
		/// <param name="value">要写入的实际数据 -&gt; The actual data to write</param>
		/// <returns>是否写入成功的结果对象 -&gt; Whether to write a successful result object</returns>
		/// <example>
		/// 假设起始地址为M100，M100,M101存储了温度，100.6℃值为1006，M102,M103存储了压力，1.23Mpa值为123，M104-M107存储了产量计数，写入如下：
		/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\SiemensFetchWriteNet.cs" region="WriteExample2" title="Write示例" />
		/// 以下是写入不同类型数据的示例
		/// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Profinet\SiemensFetchWriteNet.cs" region="WriteExample1" title="Write示例" />
		/// </example>
		// Token: 0x06000603 RID: 1539 RVA: 0x0001B8FC File Offset: 0x00019AFC
		[HslMqttApi("WriteByteArray", "")]
		public override OperateResult Write(string address, byte[] value)
		{
			OperateResult<byte[]> operateResult = SiemensFetchWriteNet.BuildWriteCommand(address, value);
			bool flag = !operateResult.IsSuccess;
			OperateResult result;
			if (flag)
			{
				result = operateResult;
			}
			else
			{
				OperateResult<byte[]> operateResult2 = base.ReadFromCoreServer(operateResult.Content);
				bool flag2 = !operateResult2.IsSuccess;
				if (flag2)
				{
					result = operateResult2;
				}
				else
				{
					OperateResult operateResult3 = SiemensFetchWriteNet.CheckResponseContent(operateResult2.Content);
					bool flag3 = !operateResult3.IsSuccess;
					if (flag3)
					{
						result = OperateResult.CreateFailedResult<byte[]>(operateResult3);
					}
					else
					{
						result = OperateResult.CreateSuccessResult();
					}
				}
			}
			return result;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensFetchWriteNet.Read(System.String,System.UInt16)" />
		// Token: 0x06000604 RID: 1540 RVA: 0x0001B978 File Offset: 0x00019B78
		[DebuggerStepThrough]
		public override Task<OperateResult<byte[]>> ReadAsync(string address, ushort length)
		{
			SiemensFetchWriteNet.<ReadAsync>d__5 <ReadAsync>d__ = new SiemensFetchWriteNet.<ReadAsync>d__5();
			<ReadAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte[]>>.Create();
			<ReadAsync>d__.<>4__this = this;
			<ReadAsync>d__.address = address;
			<ReadAsync>d__.length = length;
			<ReadAsync>d__.<>1__state = -1;
			<ReadAsync>d__.<>t__builder.Start<SiemensFetchWriteNet.<ReadAsync>d__5>(ref <ReadAsync>d__);
			return <ReadAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensFetchWriteNet.Write(System.String,System.Byte[])" />
		// Token: 0x06000605 RID: 1541 RVA: 0x0001B9CC File Offset: 0x00019BCC
		[DebuggerStepThrough]
		public override Task<OperateResult> WriteAsync(string address, byte[] value)
		{
			SiemensFetchWriteNet.<WriteAsync>d__6 <WriteAsync>d__ = new SiemensFetchWriteNet.<WriteAsync>d__6();
			<WriteAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
			<WriteAsync>d__.<>4__this = this;
			<WriteAsync>d__.address = address;
			<WriteAsync>d__.value = value;
			<WriteAsync>d__.<>1__state = -1;
			<WriteAsync>d__.<>t__builder.Start<SiemensFetchWriteNet.<WriteAsync>d__6>(ref <WriteAsync>d__);
			return <WriteAsync>d__.<>t__builder.Task;
		}

		/// <summary>
		/// 读取指定地址的byte数据<br />
		/// Reads the byte data for the specified address
		/// </summary>
		/// <param name="address">起始地址，格式为M100,I100,Q100,DB1.100 -&gt; Starting address, formatted as M100,I100,Q100,DB1.100</param>
		/// <returns>byte类型的结果对象 -&gt; Result object of type Byte</returns>
		/// <remarks>
		/// <note type="warning">
		/// 不适用于DB块，定时器，计数器的数据读取，会提示相应的错误，读取长度必须为偶数
		/// </note>
		/// </remarks>
		// Token: 0x06000606 RID: 1542 RVA: 0x0001BA1E File Offset: 0x00019C1E
		[HslMqttApi("ReadByte", "")]
		public OperateResult<byte> ReadByte(string address)
		{
			return ByteTransformHelper.GetResultFromArray<byte>(this.Read(address, 1));
		}

		/// <summary>
		/// 向PLC中写入byte数据，返回是否写入成功<br />
		/// Writes byte data to the PLC and returns whether the write succeeded
		/// </summary>
		/// <param name="address">起始地址，格式为M100,I100,Q100,DB1.100 -&gt; Starting address, formatted as M100,I100,Q100,DB1.100</param>
		/// <param name="value">要写入的实际数据 -&gt; The actual data to write</param>
		/// <returns>是否写入成功的结果对象 -&gt; Whether to write a successful result object</returns>
		// Token: 0x06000607 RID: 1543 RVA: 0x0001BA2D File Offset: 0x00019C2D
		[HslMqttApi("WriteByte", "")]
		public OperateResult Write(string address, byte value)
		{
			return this.Write(address, new byte[]
			{
				value
			});
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensFetchWriteNet.ReadByte(System.String)" />
		// Token: 0x06000608 RID: 1544 RVA: 0x0001BA40 File Offset: 0x00019C40
		[DebuggerStepThrough]
		public Task<OperateResult<byte>> ReadByteAsync(string address)
		{
			SiemensFetchWriteNet.<ReadByteAsync>d__9 <ReadByteAsync>d__ = new SiemensFetchWriteNet.<ReadByteAsync>d__9();
			<ReadByteAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult<byte>>.Create();
			<ReadByteAsync>d__.<>4__this = this;
			<ReadByteAsync>d__.address = address;
			<ReadByteAsync>d__.<>1__state = -1;
			<ReadByteAsync>d__.<>t__builder.Start<SiemensFetchWriteNet.<ReadByteAsync>d__9>(ref <ReadByteAsync>d__);
			return <ReadByteAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc cref="M:HslCommunication.Profinet.Siemens.SiemensFetchWriteNet.Write(System.String,System.Byte)" />
		// Token: 0x06000609 RID: 1545 RVA: 0x0001BA8C File Offset: 0x00019C8C
		[DebuggerStepThrough]
		public Task<OperateResult> WriteAsync(string address, byte value)
		{
			SiemensFetchWriteNet.<WriteAsync>d__10 <WriteAsync>d__ = new SiemensFetchWriteNet.<WriteAsync>d__10();
			<WriteAsync>d__.<>t__builder = AsyncTaskMethodBuilder<OperateResult>.Create();
			<WriteAsync>d__.<>4__this = this;
			<WriteAsync>d__.address = address;
			<WriteAsync>d__.value = value;
			<WriteAsync>d__.<>1__state = -1;
			<WriteAsync>d__.<>t__builder.Start<SiemensFetchWriteNet.<WriteAsync>d__10>(ref <WriteAsync>d__);
			return <WriteAsync>d__.<>t__builder.Task;
		}

		/// <inheritdoc />
		// Token: 0x0600060A RID: 1546 RVA: 0x0001BADE File Offset: 0x00019CDE
		public override string ToString()
		{
			return string.Format("SiemensFetchWriteNet[{0}:{1}]", this.IpAddress, this.Port);
		}

		/// <summary>
		/// 计算特殊的地址信息<br />
		/// Calculate special address information
		/// </summary>
		/// <param name="address">字符串信息</param>
		/// <returns>实际值</returns>
		// Token: 0x0600060B RID: 1547 RVA: 0x0001BAFC File Offset: 0x00019CFC
		private static int CalculateAddressStarted(string address)
		{
			bool flag = address.IndexOf('.') < 0;
			int result;
			if (flag)
			{
				result = Convert.ToInt32(address);
			}
			else
			{
				string[] array = address.Split(new char[]
				{
					'.'
				});
				result = Convert.ToInt32(array[0]);
			}
			return result;
		}

		// Token: 0x0600060C RID: 1548 RVA: 0x0001BB44 File Offset: 0x00019D44
		private static OperateResult CheckResponseContent(byte[] content)
		{
			bool flag = content[8] > 0;
			OperateResult result;
			if (flag)
			{
				result = new OperateResult((int)content[8], StringResources.Language.SiemensWriteError + content[8].ToString());
			}
			else
			{
				result = OperateResult.CreateSuccessResult();
			}
			return result;
		}

		/// <summary>
		/// 解析数据地址，解析出地址类型，起始地址，DB块的地址<br />
		/// Parse data address, parse out address type, start address, db block address
		/// </summary>
		/// <param name="address">起始地址，格式为M100,I100,Q100,DB1.100 -&gt; Starting address, formatted as M100,I100,Q100,DB1.100</param>
		/// <returns>解析出地址类型，起始地址，DB块的地址 -&gt; Resolves address type, start address, db block address</returns>
		// Token: 0x0600060D RID: 1549 RVA: 0x0001BB8C File Offset: 0x00019D8C
		private static OperateResult<byte, int, ushort> AnalysisAddress(string address)
		{
			OperateResult<byte, int, ushort> operateResult = new OperateResult<byte, int, ushort>();
			try
			{
				operateResult.Content3 = 0;
				bool flag = address[0] == 'I';
				if (flag)
				{
					operateResult.Content1 = 3;
					operateResult.Content2 = SiemensFetchWriteNet.CalculateAddressStarted(address.Substring(1));
				}
				else
				{
					bool flag2 = address[0] == 'Q';
					if (flag2)
					{
						operateResult.Content1 = 4;
						operateResult.Content2 = SiemensFetchWriteNet.CalculateAddressStarted(address.Substring(1));
					}
					else
					{
						bool flag3 = address[0] == 'M';
						if (flag3)
						{
							operateResult.Content1 = 2;
							operateResult.Content2 = SiemensFetchWriteNet.CalculateAddressStarted(address.Substring(1));
						}
						else
						{
							bool flag4 = address[0] == 'D' || address.Substring(0, 2) == "DB";
							if (flag4)
							{
								operateResult.Content1 = 1;
								string[] array = address.Split(new char[]
								{
									'.'
								});
								bool flag5 = address[1] == 'B';
								if (flag5)
								{
									operateResult.Content3 = Convert.ToUInt16(array[0].Substring(2));
								}
								else
								{
									operateResult.Content3 = Convert.ToUInt16(array[0].Substring(1));
								}
								bool flag6 = operateResult.Content3 > 255;
								if (flag6)
								{
									operateResult.Message = StringResources.Language.SiemensDBAddressNotAllowedLargerThan255;
									return operateResult;
								}
								operateResult.Content2 = SiemensFetchWriteNet.CalculateAddressStarted(address.Substring(address.IndexOf('.') + 1));
							}
							else
							{
								bool flag7 = address[0] == 'T';
								if (flag7)
								{
									operateResult.Content1 = 7;
									operateResult.Content2 = SiemensFetchWriteNet.CalculateAddressStarted(address.Substring(1));
								}
								else
								{
									bool flag8 = address[0] == 'C';
									if (!flag8)
									{
										operateResult.Message = StringResources.Language.NotSupportedDataType;
										operateResult.Content1 = 0;
										operateResult.Content2 = 0;
										operateResult.Content3 = 0;
										return operateResult;
									}
									operateResult.Content1 = 6;
									operateResult.Content2 = SiemensFetchWriteNet.CalculateAddressStarted(address.Substring(1));
								}
							}
						}
					}
				}
			}
			catch (Exception ex)
			{
				operateResult.Message = ex.Message;
				return operateResult;
			}
			operateResult.IsSuccess = true;
			return operateResult;
		}

		/// <summary>
		/// 生成一个读取字数据指令头的通用方法<br />
		/// A general method for generating a command header to read a Word data
		/// </summary>
		/// <param name="address">起始地址，格式为M100,I100,Q100,DB1.100 -&gt; Starting address, formatted as M100,I100,Q100,DB1.100</param>
		/// <param name="count">读取数据个数 -&gt; Number of Read data</param>
		/// <returns>带结果对象的报文数据 -&gt; Message data with a result object</returns>
		// Token: 0x0600060E RID: 1550 RVA: 0x0001BDE8 File Offset: 0x00019FE8
		public static OperateResult<byte[]> BuildReadCommand(string address, ushort count)
		{
			OperateResult<byte, int, ushort> operateResult = SiemensFetchWriteNet.AnalysisAddress(address);
			bool flag = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				byte[] array = new byte[16];
				array[0] = 83;
				array[1] = 53;
				array[2] = 16;
				array[3] = 1;
				array[4] = 3;
				array[5] = 5;
				array[6] = 3;
				array[7] = 8;
				array[8] = operateResult.Content1;
				array[9] = (byte)operateResult.Content3;
				array[10] = (byte)(operateResult.Content2 / 256);
				array[11] = (byte)(operateResult.Content2 % 256);
				bool flag2 = operateResult.Content1 == 1 || operateResult.Content1 == 6 || operateResult.Content1 == 7;
				if (flag2)
				{
					bool flag3 = count % 2 > 0;
					if (flag3)
					{
						return new OperateResult<byte[]>(StringResources.Language.SiemensReadLengthMustBeEvenNumber);
					}
					array[12] = BitConverter.GetBytes((int)(count / 2))[1];
					array[13] = BitConverter.GetBytes((int)(count / 2))[0];
				}
				else
				{
					array[12] = BitConverter.GetBytes(count)[1];
					array[13] = BitConverter.GetBytes(count)[0];
				}
				array[14] = byte.MaxValue;
				array[15] = 2;
				result = OperateResult.CreateSuccessResult<byte[]>(array);
			}
			return result;
		}

		/// <summary>
		/// 生成一个写入字节数据的指令<br />
		/// Generate an instruction to write byte data
		/// </summary>
		/// <param name="address">起始地址，格式为M100,I100,Q100,DB1.100 -&gt; Starting address, formatted as M100,I100,Q100,DB1.100</param>
		/// <param name="data">实际的写入的内容 -&gt; The actual content of the write</param>
		/// <returns>带结果对象的报文数据 -&gt; Message data with a result object</returns>
		// Token: 0x0600060F RID: 1551 RVA: 0x0001BF10 File Offset: 0x0001A110
		public static OperateResult<byte[]> BuildWriteCommand(string address, byte[] data)
		{
			bool flag = data == null;
			if (flag)
			{
				data = new byte[0];
			}
			OperateResult<byte, int, ushort> operateResult = SiemensFetchWriteNet.AnalysisAddress(address);
			bool flag2 = !operateResult.IsSuccess;
			OperateResult<byte[]> result;
			if (flag2)
			{
				result = OperateResult.CreateFailedResult<byte[]>(operateResult);
			}
			else
			{
				byte[] array = new byte[16 + data.Length];
				array[0] = 83;
				array[1] = 53;
				array[2] = 16;
				array[3] = 1;
				array[4] = 3;
				array[5] = 3;
				array[6] = 3;
				array[7] = 8;
				array[8] = operateResult.Content1;
				array[9] = (byte)operateResult.Content3;
				array[10] = (byte)(operateResult.Content2 / 256);
				array[11] = (byte)(operateResult.Content2 % 256);
				bool flag3 = operateResult.Content1 == 1 || operateResult.Content1 == 6 || operateResult.Content1 == 7;
				if (flag3)
				{
					bool flag4 = data.Length % 2 != 0;
					if (flag4)
					{
						return new OperateResult<byte[]>(StringResources.Language.SiemensReadLengthMustBeEvenNumber);
					}
					array[12] = BitConverter.GetBytes(data.Length / 2)[1];
					array[13] = BitConverter.GetBytes(data.Length / 2)[0];
				}
				else
				{
					array[12] = BitConverter.GetBytes(data.Length)[1];
					array[13] = BitConverter.GetBytes(data.Length)[0];
				}
				array[14] = byte.MaxValue;
				array[15] = 2;
				Array.Copy(data, 0, array, 16, data.Length);
				result = OperateResult.CreateSuccessResult<byte[]>(array);
			}
			return result;
		}
	}
}
